//! gRPC客户端实现
//! 
//! 提供SandboxManagerService的客户端封装，方便其他服务调用

use std::time::Duration;
use tonic::transport::{Channel, Endpoint};
use tonic::{Request, Status};
use anyhow::Result;

use crate::grpc::proto::{
    sandbox_manager_service_client::SandboxManagerServiceClient,
    SandboxRequest, SandboxInfo, ExecutionRequest, ExecutionResult,
    ReleaseSandboxRequest, ReleaseResponse, SandboxStatusRequest, SandboxStatus,
    SystemStatsRequest, SystemStats, HealthCheckRequest, HealthCheckResponse,
    Language, Priority, ResourceRequirements,
};

/// gRPC客户端封装
pub struct SandboxManagerClient {
    client: SandboxManagerServiceClient<Channel>,
}

impl SandboxManagerClient {
    /// 连接到gRPC服务器
    pub async fn connect<D>(dst: D) -> Result<Self>
    where
        D: TryInto<Endpoint>,
        D::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
    {
        let endpoint = dst.try_into().map_err(|e| anyhow::anyhow!("无效的端点: {}", e.into()))?;
        
        let channel = endpoint
            .connect_timeout(Duration::from_secs(5))
            .timeout(Duration::from_secs(30))
            .connect()
            .await
            .map_err(|e| anyhow::anyhow!("连接失败: {}", e))?;
        
        let client = SandboxManagerServiceClient::new(channel);
        
        Ok(Self { client })
    }

    /// 分配沙箱
    pub async fn allocate_sandbox(
        &mut self,
        language: Language,
        version: String,
        resources: Option<ResourceRequirements>,
        timeout_seconds: u32,
        priority: Priority,
    ) -> Result<SandboxInfo> {
        let request = Request::new(SandboxRequest {
            language: language as i32,
            version,
            resources,
            timeout_seconds,
            priority: priority as i32,
        });

        let response = self.client
            .allocate_sandbox(request)
            .await
            .map_err(|e| anyhow::anyhow!("分配沙箱失败: {}", e))?;

        Ok(response.into_inner())
    }

    /// 执行代码
    pub async fn execute_code(
        &mut self,
        sandbox_id: String,
        source_code: String,
        language: Language,
        entry_point: String,
        env_vars: std::collections::HashMap<String, String>,
        stdin: String,
        timeout_ms: u32,
    ) -> Result<ExecutionResult> {
        let request = Request::new(ExecutionRequest {
            sandbox_id,
            source_code,
            language: language as i32,
            entry_point,
            dependencies: vec![], // 简化实现，可扩展
            env_vars,
            stdin,
            timeout_ms,
        });

        let response = self.client
            .execute_code(request)
            .await
            .map_err(|e| anyhow::anyhow!("执行代码失败: {}", e))?;

        Ok(response.into_inner())
    }

    /// 释放沙箱
    pub async fn release_sandbox(&mut self, sandbox_id: String) -> Result<ReleaseResponse> {
        let request = Request::new(ReleaseSandboxRequest { sandbox_id });

        let response = self.client
            .release_sandbox(request)
            .await
            .map_err(|e| anyhow::anyhow!("释放沙箱失败: {}", e))?;

        Ok(response.into_inner())
    }

    /// 获取沙箱状态
    pub async fn get_sandbox_status(&mut self, sandbox_id: String) -> Result<SandboxStatus> {
        let request = Request::new(SandboxStatusRequest { sandbox_id });

        let response = self.client
            .get_sandbox_status(request)
            .await
            .map_err(|e| anyhow::anyhow!("获取沙箱状态失败: {}", e))?;

        Ok(response.into_inner())
    }

    /// 获取系统统计信息
    pub async fn get_system_stats(&mut self) -> Result<SystemStats> {
        let request = Request::new(SystemStatsRequest {});

        let response = self.client
            .get_system_stats(request)
            .await
            .map_err(|e| anyhow::anyhow!("获取系统统计失败: {}", e))?;

        Ok(response.into_inner())
    }

    /// 健康检查
    pub async fn health_check(&mut self) -> Result<HealthCheckResponse> {
        let request = Request::new(HealthCheckRequest {});

        let response = self.client
            .health_check(request)
            .await
            .map_err(|e| anyhow::anyhow!("健康检查失败: {}", e))?;

        Ok(response.into_inner())
    }
}

/// 构建器模式的客户端配置
pub struct SandboxManagerClientBuilder {
    endpoint: String,
    connect_timeout: Duration,
    timeout: Duration,
}

impl SandboxManagerClientBuilder {
    /// 创建新的客户端构建器
    pub fn new(endpoint: impl Into<String>) -> Self {
        Self {
            endpoint: endpoint.into(),
            connect_timeout: Duration::from_secs(5),
            timeout: Duration::from_secs(30),
        }
    }

    /// 设置连接超时时间
    pub fn connect_timeout(mut self, timeout: Duration) -> Self {
        self.connect_timeout = timeout;
        self
    }

    /// 设置请求超时时间
    pub fn timeout(mut self, timeout: Duration) -> Self {
        self.timeout = timeout;
        self
    }

    /// 构建客户端
    pub async fn build(self) -> Result<SandboxManagerClient> {
        let endpoint = Endpoint::from_shared(self.endpoint)
            .map_err(|e| anyhow::anyhow!("无效的端点: {}", e))?
            .connect_timeout(self.connect_timeout)
            .timeout(self.timeout);

        let channel = endpoint
            .connect()
            .await
            .map_err(|e| anyhow::anyhow!("连接失败: {}", e))?;

        let client = SandboxManagerServiceClient::new(channel);

        Ok(SandboxManagerClient { client })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::grpc::proto::{Language, Priority, ResourceRequirements};

    #[tokio::test]
    async fn test_client_builder() {
        let builder = SandboxManagerClientBuilder::new("http://127.0.0.1:50051")
            .connect_timeout(Duration::from_secs(3))
            .timeout(Duration::from_secs(10));

        // 注意: 这个测试需要实际的服务器运行才能通过
        let _result = builder.build().await;
        // assert!(result.is_ok());
    }

    #[test]
    fn test_client_request_creation() {
        let request = SandboxRequest {
            language: Language::Python as i32,
            version: "3.9".to_string(),
            resources: Some(ResourceRequirements {
                memory_mb: 512,
                cpu_cores: 1,
                disk_mb: 1024,
                network_enabled: true,
            }),
            timeout_seconds: 300,
            priority: Priority::Normal as i32,
        };

        assert_eq!(request.language, Language::Python as i32);
        assert_eq!(request.version, "3.9");
        assert_eq!(request.timeout_seconds, 300);
    }
}